#include <iostream>
#include <string>
#include <unistd.h>
#include <ctype.h>
#include <unordered_map>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"

static void Usage(const std::string porc)
{
  std::cout << "Usage:\n\t" << porc << "port [ip]" << std::endl;
}

//云服务器禁止bind确定的ip 只能使用INADDR_ANY
class UdpServer{
public:
  UdpServer(int port, std::string ip = ""):_port(port), _ip(ip), _sockfd(-1)
  {}
  ~UdpServer()
  {}
public:
  void init()
  {
    //创建套接字
    _sockfd = socket(AF_INET, SOCK_DGRAM, 0);//属于 用户层 
    if(_sockfd < 0)
    {
      logMessage(FATAL, "socket:%s,%d", strerror(errno), _sockfd);
      exit(1);
    }
    logMessage(DEBUG, "socket create success: %d", _sockfd);
    //bind端口号和ip
    //填写网络套接字信息
    struct sockaddr_in local;
    bzero(&local, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_port = htons(_port);
    local.sin_addr.s_addr = _ip.empty() ? htonl(INADDR_ANY) : inet_addr(_ip.c_str());
    //bind网络
    if(bind(_sockfd, (const struct sockaddr*)&local, sizeof(local)) == -1) //属于网络层
    {
      logMessage(FATAL, "bind: %s:%d", strerror(errno), _sockfd);
      exit(2);
    }
    logMessage(DEBUG, "socket bind success: %d", _sockfd);

  }
  void start()
  {
    char inbuffer[1024];//read
    char outbuffer[1024];//send
    while(true)
    {
      //ssize_t s = read(_sockfd, inbuffer, sizeof(inbuffer) - 1);
      struct sockaddr_in peer;
      socklen_t len = sizeof(peer);
      ssize_t s = recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr*)&peer, &len);
      if(s > 0)
      {
        inbuffer[s] = '\0';
      }
      else if(s == -1)
      {
        logMessage(WARINING, "recvfrom :%s:%d",strerror(errno), _sockfd);
        continue;
      }
      //写入用户表
      std::string peerIp = inet_ntoa(peer.sin_addr);
      uint32_t peerPort = ntohs(peer.sin_port);
      checkOnlineUser(peerIp, peerPort, peer);
      
      logMessage(NOTICE, "[%s:%d]# %s", peerIp.c_str(), peerPort, inbuffer);

      messageRoute(peerIp, peerPort, inbuffer);

    }

  }

  void checkOnlineUser(std::string &ip, uint32_t port, struct sockaddr_in &peer)
  {
    std::string key = ip;
    key += ":";
    key += std::to_string(port);
    auto iter = _users.find(key);
    if(iter == _users.end())
    {
      _users.insert({key,peer});
    }

  }

  void messageRoute(std::string &ip, uint32_t port, std::string info)
  {
    std::string message = "[";
    message += ip;
    message += ":";
    message += std::to_string(port);
    message += "]# ";
    message += info;

    for(auto &user : _users)
    {
      sendto(_sockfd, message.c_str(), message.size(), 0,(struct sockaddr*)&(user.second), sizeof(user.second));
    }
  }
private:
  //端口
  uint16_t _port;
  //ip
  std::string _ip;
  //服务器的sockfd
  int _sockfd;
  //用户表
  std::unordered_map<std::string, struct sockaddr_in> _users;
};

// ./Server port ip
int main(int argc, char *argv[])
{
  if(argc != 2 && argc != 3)
  {
    Usage("Server");
    exit(3);
  }
  uint16_t port = atoi(argv[1]);
  std::string ip = "";
  if(argc == 3)
  {
    ip = argv[2];
  }

  UdpServer Server(port,ip);
  Server.init();
  Server.start();

  return 0;
}
